package main

import (
	"flag"
	"github.com/jinzhu/configor"
	"log"
	"moss/api"
	"moss/conf"
	"moss/meta"
	"moss/restful"
	"os"
	"os/signal"
	"path"
	"path/filepath"
	"strings"
	"time"
)

func loadConfigFile(confLocation string) {
	_, err := os.Stat(confLocation)
	if err != nil {
		log.Fatalln("os.stat failed:", err)
		os.Exit(-1)
	}
	err = configor.Load(&conf.Config, confLocation)
	if err != nil {
		log.Fatalln("configor.Load failed:", err)
		os.Exit(-1)
	}
}

func registerTimer(callback func(), interval time.Duration) {
	go func() {
		for {
			callback()
			chanTimeout := time.After(interval)
			<-chanTimeout
		}
	}()
}

func registerAtClosing(callback func()) {
	closingChan := make(chan os.Signal, 1)
	signal.Notify(closingChan, os.Interrupt)

	go func() {
		<-closingChan
		callback()
		log.Println("RESTful HTTP Server stopped. Bye.")
		os.Exit(0)
	}()
}

func connectDatabase(dbLocation string) {
	_, err := os.Stat(dbLocation)
	if os.IsNotExist(err) {
		log.Fatalln("Running prepare-util before executing server daemon")
		os.Exit(-1)
	}

	err = meta.Bind(dbLocation)
	if err != nil {
		log.Fatalln("db.Bind failed:", err)
		os.Exit(-1)
	}
	
	// Once touched, never modify
	meta.CreateDatabaseTables()
}

func currentDirectory() string {
	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		log.Fatal(err)
	}
	return strings.Replace(dir, "\\", "/", -1)
}

func closingRoutine() {
	meta.Close()
	if destroyAtClosing {
		os.Remove(conf.Config.Path.MetaFile)
		os.RemoveAll(conf.Config.Path.Data)
	}
	os.RemoveAll(conf.Config.Path.Temp)
}

var (
	confLocation     string
	destroyAtClosing bool
	showHelp         bool
	httpPort         uint
)

func parseArgs() {
	defaultConfLocation := path.Join(currentDirectory(), "config.yml")
	flag.BoolVar(&showHelp, "h", false, "Show help information.")
	flag.StringVar(&confLocation, "c", defaultConfLocation, "Specify configuration file.")
	flag.BoolVar(&destroyAtClosing, "d", false, "All files destroyed when exited. [DANGEROUS]")
	flag.UintVar(&httpPort, "p", 8080, "Port number that RESTful HTTP server will used.")

	flag.Parse()
	if showHelp {
		flag.Usage()
		os.Exit(0)
	}
}

func main() {
	parseArgs()
	loadConfigFile(confLocation)
	dbLocation := conf.Config.Path.MetaFile
	connectDatabase(dbLocation)
	registerAtClosing(closingRoutine)
	registerTimer(api.UpdateLoggingRoutine, time.Hour)
	registerTimer(api.LifeCycleRoutine, time.Hour)
	log.Println("RESTful HTTP Server started!")
	restful.StartHttpServer(uint16(httpPort))
}
